#include "SocketOpt.h"
#include "Network.h"


using namespace tmms::network;

SocketOpt::SocketOpt(int sock,bool v6)
:sock_(sock),is_ipv6_(v6)
{ //创建socket，他有两种类型，一种是tcp的，一种是upd的

}


int SocketOpt::CreateNonblockingTcpSocket(int family)
{//创建tcp协议的socket，静态函数，返回socket
    int sock = ::socket(family,SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC,IPPROTO_TCP);
    if(sock<0)
    {
        NEWORK_ERROR<<"socket failed.";
    }
    return sock;
}

int SocketOpt::createNonblockingUdpSocket(int family)
{//创建udp协议的socket，静态函数，返回socket

    int sock = ::socket(family,SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC,IPPROTO_UDP);
    if(sock<0)
    {
        NEWORK_ERROR<<"socket failed.";
    }
    return sock;
}



int  SocketOpt::BindAddress(const InetAddress& localaddr)
{ //为当前socket bind端口
    if(localaddr.IsIpV6())
    {
        struct sockaddr_in6 addr;
        localaddr.GetSockAddr((struct sockaddr*)&addr);
        socklen_t size = sizeof(struct sockaddr_in6);
        return ::bind(sock_,(struct sockaddr*)&addr,size);  
    }
    else{
        struct sockaddr_in addr;
        localaddr.GetSockAddr((struct sockaddr*)&addr);
        socklen_t size = sizeof(struct sockaddr_in);
        return ::bind(sock_,(struct sockaddr*)&addr,size);  
    }

}

int  SocketOpt::Listen() //开启监听
{

    return ::listen(sock_,SOMAXCONN);
}

int SocketOpt::Accept(InetAddress *peeraddr)
{
    struct  sockaddr_in6 addr;
    socklen_t len =sizeof(struct sockaddr_in6);
    std::cout<<"w9999 "<<std::endl;
    int sock = ::accept4(sock_,(struct sockaddr*)&addr,&len,SOCK_CLOEXEC|SOCK_NONBLOCK);//通过封装 Linux 系统调用 accept4() 实现了对已建立连接的客户端的接收，其核心机制依赖于内核的​​连接队列管理​​和​​非阻塞套接字操作
    /*内核会从 ​​Accept队列的头部取出一个已完成的连接​​，并创建一个​​新的套接字描述符​​（sock > 0）用于与该客户端通信*/
    if(sock>0)
    {
        if(addr.sin6_family ==AF_INET)//IPv4 网络协议
        {
            char ip[INET_ADDRSTRLEN] = {0,};
            struct  sockaddr_in * saddr =(struct sockaddr_in *)&addr;//将通用套接字地址结构 addr 强制转换为 IPv4 专用结构 sockaddr_in 的指针​​
            ::inet_ntop(AF_INET,&(saddr->sin_addr.s_addr),ip,sizeof(ip));//此函数用于​​将二进制 IPv6 地址转换为可读字符串​​
            peeraddr->SetAddr(ip);
            peeraddr->SetPort(ntohs(saddr->sin_port));
        }
        else if(addr.sin6_family ==AF_INET6){ //IPv6 网络协议
            char ip[INET6_ADDRSTRLEN] = {0,};
            struct  sockaddr_in * saddr =(struct sockaddr_in *)&addr;
            ::inet_ntop(AF_INET6,&(addr.sin6_addr),ip,sizeof(ip));
            peeraddr->SetAddr(ip);
            peeraddr->SetPort(ntohs(addr.sin6_port));
            peeraddr->SetIsIPV6(true);
        }
    }
    return sock;
}


//客户端
int SocketOpt::Connetct(const InetAddress &addr)
{
    struct sockaddr_in addr_in;
    addr.GetSockAddr((struct sockaddr *)&addr_in);
    return ::connect(sock_,(struct sockaddr *)&addr_in,sizeof(struct sockaddr_in));
}
//获取地址
InetAddressPtr SocketOpt::GetLocalAddr()
{
    struct sockaddr_in6 addr_in;
    socklen_t len =sizeof(struct sockaddr_in6);
    ::getsockname(sock_,(struct  sockaddr*)&addr_in,&len);//​​getsockname()​​	获取​​本地​​地址
    InetAddressPtr peeraddr = std::make_shared<InetAddress> ();

    if(addr_in.sin6_family ==AF_INET)//IPv4 网络协议
    {
        char ip[INET_ADDRSTRLEN] = {0,};
        struct  sockaddr_in * saddr =(struct sockaddr_in *)&addr_in;//将通用套接字地址结构 addr 强制转换为 IPv4 专用结构 sockaddr_in 的指针​​
        ::inet_ntop(AF_INET,&(saddr->sin_addr.s_addr),ip,sizeof(ip));//此函数用于​​将二进制 IPv6 地址转换为可读字符串​​
        peeraddr->SetAddr(ip);
        peeraddr->SetPort(ntohs(saddr->sin_port));
    }
    else if(addr_in.sin6_family ==AF_INET6){ //IPv6 网络协议
        char ip[INET6_ADDRSTRLEN] = {0,};
        ::inet_ntop(AF_INET6,&(addr_in.sin6_addr),ip,sizeof(ip));
        peeraddr->SetAddr(ip);
        peeraddr->SetPort(ntohs(addr_in.sin6_port));
        peeraddr->SetIsIPV6(true);
    }
    return peeraddr;
}

InetAddressPtr SocketOpt::GetPeerAddr()
{
    struct sockaddr_in6 addr_in;
    socklen_t len =sizeof(struct sockaddr_in6);
    ::getpeername(sock_,(struct  sockaddr*)&addr_in,&len);//getpeername()​​	获取​​远端​​地址	仅限已建立连接的套接字
    InetAddressPtr peeraddr = std::make_shared<InetAddress> ();

    if(addr_in.sin6_family ==AF_INET)//IPv4 网络协议
    {
        char ip[INET_ADDRSTRLEN] = {0,};
        struct  sockaddr_in * saddr =(struct sockaddr_in *)&addr_in;//将通用套接字地址结构 addr 强制转换为 IPv4 专用结构 sockaddr_in 的指针​​
        ::inet_ntop(AF_INET,&(saddr->sin_addr.s_addr),ip,sizeof(ip));//此函数用于​​将二进制 IPv6 地址转换为可读字符串​​
        peeraddr->SetAddr(ip);
        peeraddr->SetPort(ntohs(saddr->sin_port));
    }
    else if(addr_in.sin6_family ==AF_INET6){ //IPv6 网络协议
        char ip[INET6_ADDRSTRLEN] = {0,};
        ::inet_ntop(AF_INET6,&(addr_in.sin6_addr),ip,sizeof(ip));
        peeraddr->SetAddr(ip);
        peeraddr->SetPort(ntohs(addr_in.sin6_port));
        peeraddr->SetIsIPV6(true);
    }
    return peeraddr;
}


void SocketOpt::SetTcpNoDelay(bool on)
{
    int optvalue = on ? 1:0;
    ::setsockopt(sock_,IPPROTO_TCP,TCP_NODELAY,&optvalue,sizeof(optvalue));
}
void SocketOpt::SetReuseAddr(bool on )
{
    int optvalue = on ? 1:0;
    ::setsockopt(sock_,SOL_SOCKET,SO_REUSEADDR,&optvalue,sizeof(optvalue));
}
void SocketOpt::SetReusePort(bool on )
{
    int optvalue = on ? 1:0;
    ::setsockopt(sock_,SOL_SOCKET,SO_REUSEPORT,&optvalue,sizeof(optvalue));
}
void SocketOpt::SetkeepAlive(bool on )
{
    int optvalue = on ? 1:0;
    ::setsockopt(sock_,SOL_SOCKET,SO_KEEPALIVE,&optvalue,sizeof(optvalue));
}

void SocketOpt::SetNooBlocking(bool on)
{
    int flag  = ::fcntl (sock_,F_GETFL,0);
    if(on){
        flag|= O_NONBLOCK;
    }else{
        flag &=~O_NONBLOCK;
    }
    ::fcntl(sock_,F_SETFL,flag);
    // int optvalue = on ? 1:0;
    // ::setsockopt(sock_,SOL_SOCKET,SOCK_NONBLOCK,&optvalue,sizeof(optvalue));
}
